﻿using System;
using System.Threading;
using OdaOperation.Model;
using Teigha.Core;
using Teigha.TD;

namespace OdaOperation.Core.Creators
{
    /// <summary>
    /// 
    /// </summary>
    public class TableItemCreator : BaseCreator
    {
        /// <summary>
        /// 块表对象
        /// </summary>
        private OdDbBlockTable m_blockTable;
        /// <summary>
        /// 文本样式对象
        /// </summary>
        private OdDbObjectId m_textStyle;
        /// <summary>
        /// 位置
        /// </summary>
        private OdGePoint3d m_location;
        /// <summary>
        /// X轴方向向量
        /// </summary>
        private OdGeVector3d m_xAxis;
        /// <summary>
        /// Y轴方向向量
        /// </summary>
        private OdGeVector3d m_yAxis;
        /// <summary>
        /// 字体大小
        /// </summary>
        private double m_fontSize;

        /// <summary>
        ///   构造函数，初始化块表对象
        /// </summary>
        /// <param name="pDb"></param>
        public TableItemCreator(OdDbDatabase pDb)
            : base(pDb)
        {
            m_blockTable = m_database.getBlockTableId().openObject() as OdDbBlockTable;
        }
        /// <summary>
        ///   构造函数，初始化各个属性
        /// </summary>
        /// <param name="pDb"></param>
        /// <param name="blockTableRecord"></param>
        /// <param name="layerName"></param>
        /// <param name="textStyle"></param>
        /// <param name="location"></param>
        /// <param name="xAxis"></param>
        /// <param name="yAxis"></param>
        /// <param name="fontSize"></param>
        public TableItemCreator(OdDbDatabase pDb, OdDbObjectId blockTableRecord, string layerName, OdDbObjectId textStyle, OdGePoint3d location, OdGeVector3d xAxis, OdGeVector3d yAxis, double fontSize = 12.0)
            : base(pDb, blockTableRecord, layerName)
        {
            m_textStyle = textStyle;
            m_location = location;
            m_xAxis = xAxis;
            m_yAxis = yAxis;
            m_fontSize = fontSize;
        }

        /// <summary>
        /// 创建表格项的方法，接收表格项对象和位置参数
        /// </summary>
        /// <param name="item"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="top"></param>
        /// <param name="bottom"></param>
        public void Create(TableItem item, double left, double right, double top, double bottom)
        {
            
            Create(m_blockTableId, m_layerName, m_textStyle, m_location, m_xAxis, m_yAxis, item, double.IsNaN(item.FontSize) ? m_fontSize : item.FontSize, left, right, top, bottom);
        }

        /// <summary>
        /// 创建表格项的方法，接收更多参数
        /// </summary>
        /// <param name="blockTableId"></param>
        /// <param name="layerName"></param>
        /// <param name="textStyle"></param>
        /// <param name="location"></param>
        /// <param name="xAxis"></param>
        /// <param name="yAxis"></param>
        /// <param name="item"></param>
        /// <param name="fontSize"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="top"></param>
        /// <param name="bottom"></param>
        /// <exception cref="NullReferenceException"></exception>
        public void Create(OdDbObjectId blockTableId, string layerName, OdDbObjectId textStyle, OdGePoint3d location, OdGeVector3d xAxis, OdGeVector3d yAxis, TableItem item, double fontSize, double left, double right, double top, double bottom)
        {
           
            m_blockTable = m_database.getBlockTableId().openObject() as OdDbBlockTable;
            OdDbBlockTableRecord odDbBlockTableRecord = blockTableId.openObject(OpenMode.kForWrite) as OdDbBlockTableRecord;

            if (string.IsNullOrWhiteSpace(item.Value))
            {
                // 如果值为空，则返回
                return;
            }

            if (item.IsBlock)
            {
                // 如果是块
                if (m_blockTable.has(item.Value))
                {
                    // 如果块表中存在该块
                    OdDbObjectId at = m_blockTable.getAt(item.Value);
                    OdDbBlockReference odDbBlockReference = OdDbBlockReference.createObject();
                    odDbBlockReference.setBlockTableRecord(at);
                    odDbBlockReference.setDatabaseDefaults(m_database);
                    odDbBlockReference.setLayer(layerName, doSubents: true);
                    odDbBlockTableRecord.appendOdDbEntity(odDbBlockReference);

                    OdGeExtents3d odGeExtents3d = new OdGeExtents3d();
                    odDbBlockReference.getGeomExtents(odGeExtents3d);
                    double num = odGeExtents3d.maxPoint().y - odGeExtents3d.minPoint().y;
                    double num2 = odGeExtents3d.maxPoint().x - odGeExtents3d.minPoint().x;
                    OdGePoint3d point = new OdGePoint3d((odGeExtents3d.maxPoint().x + odGeExtents3d.minPoint().x) * 0.5, (odGeExtents3d.maxPoint().y + odGeExtents3d.minPoint().y) * 0.5, (odGeExtents3d.maxPoint().z + odGeExtents3d.minPoint().z) * 0.5);
                    OdGeMatrix3d odGeMatrix3d = new OdGeMatrix3d();
                    double num3 = (double.IsNaN(item.Padding) ? 1.0 : item.Padding);
                    double num4 = Math.Min((Math.Abs(top - bottom) - num3 * 2.0) / num, (Math.Abs(right - left) - num3 * 2.0) / num2);
                    OdGeVector3d odGeVector3d = new OdGeVector3d(0.0, 0.0, 0.0);
                    double num5 = (Math.Abs(right - left) - num2 * num4) * 0.5;
                    double num6 = (Math.Abs(top - bottom) - num * num4) * 0.5;

                    if (TableAlignment.Left == (item.Align & TableAlignment.Left))
                    {
                        odGeVector3d.x = num3 - num5;
                    }

                    if (TableAlignment.Right == (item.Align & TableAlignment.Right))
                    {
                        odGeVector3d.x = num5 - num3;
                    }

                    if (TableAlignment.Bottom == (item.Align & TableAlignment.Bottom))
                    {
                        odGeVector3d.y = num3 - num6;
                    }

                    if (TableAlignment.Top == (item.Align & TableAlignment.Top))
                    {
                        odGeVector3d.y = num6 - num3;
                    }

                    OdGePoint3d odGePoint3d = new OdGePoint3d(location).Add(new OdGeVector3d(xAxis).Mul((left + right) * 0.5).Add(new OdGeVector3d(yAxis).Mul((top + bottom) * 0.5))).Add(odGeVector3d);
                    odGeMatrix3d.setTranslation(odGePoint3d.Sub(point));
                    OdGeMatrix3d odGeMatrix3d2 = new OdGeMatrix3d();
                    odGeMatrix3d2.setToScaling(num4, odGePoint3d);
                    odDbBlockReference.transformBy(odGeMatrix3d);
                    odDbBlockReference.transformBy(odGeMatrix3d2);
                    return;
                }

                throw new NullReferenceException("块" + item.Value + "不存在");
            }

            // 如果不是块，则创建MText
            MemoryTransaction value = MemoryManager.GetMemoryManager().StartTransaction(Thread.CurrentThread.ManagedThreadId);
            OdDbMText odDbMText = OdDbMText.createObject();

            if (textStyle != null)
            {
                odDbMText.setTextStyle(textStyle);
            }

            OdGeExtents3d odGeExtents3d2 = new OdGeExtents3d();
            odDbMText.setHeight(fontSize);
            odDbMText.setTextHeight(fontSize);
            odDbMText.setDatabaseDefaults(m_database);
            odDbMText.setContents(item.Value);

            if (yAxis.y > 0.0)
            {
                odDbMText.setAttachment(OdDbMText.AttachmentPoint.kBottomLeft);
            }
            else
            {
                odDbMText.setAttachment(OdDbMText.AttachmentPoint.kTopLeft);
            }

            OdDbObjectId odDbObjectId = odDbBlockTableRecord.appendOdDbEntity(odDbMText);
            MemoryManager.GetMemoryManager().StopTransaction(value);
            odDbMText = odDbObjectId.openObject(OpenMode.kForWrite) as OdDbMText;
            odDbMText.getGeomExtents(odGeExtents3d2);

            double num7 = (double.IsNaN(item.Padding) ? 1.0 : item.Padding);
            double num8 = odGeExtents3d2.maxPoint().y - odGeExtents3d2.minPoint().y;
            double num9 = odGeExtents3d2.maxPoint().x - odGeExtents3d2.minPoint().x;
            double num10 = num9 / (double)item.Value.Length;
            int num11 = 0;

            for (int i = 0; i < item.Value.Length; i++)
            {
                if (item.Value[i] >= '一' && item.Value[i] <= '龥')
                {
                    num11++;
                }
            }

            num9 = (double)num11 * num10 * 0.5 + (double)(item.Value.Length - num11) * num10;

            double scale = left + num7;
            double scale2 = top - num8 - num7;

            if (TableAlignment.hCenter == (item.Align & TableAlignment.hCenter))
            {
                scale = (left + right) * 0.5 - num9 * 0.5;
            }

            if (TableAlignment.Right == (item.Align & TableAlignment.Right))
            {
                scale = right - num9 - num7;
            }

            if (TableAlignment.vCenter == (item.Align & TableAlignment.vCenter))
            {
                scale2 = (top + bottom) * 0.5 - num8 * 0.5;
            }

            if (TableAlignment.Bottom == (item.Align & TableAlignment.Bottom))
            {
                scale2 = bottom + num7;
            }

            OdGePoint3d location2 = new OdGePoint3d(location).Add(new OdGeVector3d(xAxis).Mul(scale)).Add(new OdGeVector3d(yAxis).Mul(scale2));
            odDbMText.setLocation(location2);
            odDbMText.setLayer(layerName);
        }
    }

}